import requests,time,qrcode,re,os,json,random
from PIL import Image
from pyzbar.pyzbar import decode
from util.pf import printf
class QQ():
    def __init__(self):
        self.skey = None
        self.pt4_token = None
        self.g_tk = None #g_tk
        self.p_skey = None #最重要的身份令牌
        self.p_uin = None #QQ号
        self.cookies = None #cookies
        self.headers = None #请求头
        self.QQ = None
        self.a_info = [] #[[name,amblue_id,pre,total],...]
        self.p_info = [] #[[name,url,shottime,uploadtime,type],...]
        self.videos = [] #[[name,url,shottime,uploadtime,type],...]
        if not os.path.exists('user'):
            os.mkdir('user')
    def ptqrToken(self,qrsig):
        #计算ptqrtoken
        n,i,e = len(qrsig),0,0

        while n > i:
            e += (e << 5) + ord(qrsig[i])
            i += 1

        return 2147483647 & e
    def QR(self):
        #获取 qq空间 二维码
        url = 'https://ssl.ptlogin2.qq.com/ptqrshow?appid=549000912&e=2&l=M&s=3&d=72&v=4&t=0.8692955245720428&daid=5&pt_3rd_aid=0'

        try:
            r = requests.get(url)
            qrsig = requests.utils.dict_from_cookiejar(r.cookies).get('qrsig')

            with open('QR.png', 'wb') as f:
                f.write(r.content)

            im = Image.open('QR.png')
            im = im.resize((350, 350))
            printf('登录二维码获取成功',color='green')
            decoded_objects = decode(im)
            for obj in decoded_objects:
                qr = qrcode.QRCode()
                qr.add_data(obj.data.decode('utf-8'))
                qr.print_ascii(invert=True)

            return qrsig

        except Exception as e:
            printf(e,color='red')

    def cookie(self):
        qrsig = self.QR()
        ptqrtoken = self.ptqrToken(qrsig)

        while True:
            url = 'https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&ptqrtoken=' + str(ptqrtoken) + '&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-' + str(time.time()) + '&js_ver=20032614&js_type=1&login_sig=&pt_uistyle=40&aid=549000912&daid=5&'
            cookies = {'qrsig': qrsig}

            try:
                r = requests.get(url, cookies=cookies)

                if '二维码未失效' in r.text:
                    pass

                elif '二维码认证中' in r.text:
                    printf('二维码认证中',end='')

                elif '二维码已失效' in r.text:
                    printf('二维码已失效',color='red')
                    time.sleep(2)
                    exit()

                else:
                    cookies = requests.utils.dict_from_cookiejar(r.cookies)
                    uin = requests.utils.dict_from_cookiejar(r.cookies).get('uin')
                    regex = re.compile(r'ptsigx=(.*?)&')
                    sigx = re.findall(regex, r.text)[0]
                    url = 'https://ptlogin2.qzone.qq.com/check_sig?pttype=1&uin=' + uin + '&service=ptqrlogin&nodirect=0&ptsigx=' + sigx + '&s_url=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&f_url=&ptlang=2052&ptredirect=100&aid=549000912&daid=5&j_later=0&low_login_hour=0&regmaster=0&pt_login_type=3&pt_aid=0&pt_aaid=16&pt_light=0&pt_3rd_aid=0'

                    try:
                        r = requests.get(url, cookies=cookies, allow_redirects=False)
                        targetCookies = requests.utils.dict_from_cookiejar(r.cookies)
                        #pSkey = requests.utils.dict_from_cookiejar(r.cookies).get('p_skey')
                        break

                    except Exception as e:
                        pass

            except Exception as e:
                pass

            time.sleep(3)

        return targetCookies
    def getG_tk(self,p_skey):
        hash_value = 5381
        for char in p_skey:
            hash_value += (hash_value << 5) + ord(char)
        return hash_value & 0x7FFFFFFF
    def login(self):
        def infunc():
            users = os.listdir('user')
            if not len(users) == 0:
                folder = [user for user in users if os.path.isdir('user/'+user)]
                for user in folder:
                    if os.path.exists('user/{}/cookies.json'.format(str(user))) and os.path.exists('user/{}/headers.json'.format(str(user))):
                        pass
                    else:
                        os.remove('user/{}'.format(user))
                printf('检测到{}个用户'.format(len(folder)))
                for i in range(len(folder)):
                    print("[{}] {}".format(i+1,folder[i]))
                while True:
                    try:
                        printf('请输入用户序号，输入0重新登陆：',end="")
                        num = int(input())-1
                        if num >= len(folder) or num < -1:
                            printf("输入错误！",color='red')
                            continue
                        break
                    except KeyboardInterrupt:
                        printf("已退出",color='red')
                    except:
                        printf("输入错误！",color='red')
                if int(num) == -1:
                    return 0
                self.QQ = folder[num]
                self.cookies = json.load(open('user/{}/cookies.json'.format(str(self.QQ)),'r'))
                self.headers = json.load(open('user/{}/headers.json'.format(str(self.QQ)),'r'))
                self.g_tk = self.getG_tk(self.cookies.get('p_skey'))
                self.p_skey = self.cookies.get('p_skey')
                self.skey = self.cookies.get('skey')
                self.pt4_token = self.cookies.get('pt4_token')
                if json.loads(self.get_album())['code'] == 0:
                    printf("登陆成功！",color='green')
                    return 1             
                return 0 # 登陆过期
            else:
                return 0 # 没有用户
        r = infunc()
        if r != 0:
            return r
        cookies = self.cookie()
        printf("登陆成功！",color='green')
        try:
            os.remove('QR.png')
        except:
            pass
        self.QQ = cookies.get('uin').replace('o','')
        self.skey = cookies.get('skey')
        self.p_skey = cookies.get('p_skey')
        self.g_tk = self.getG_tk(self.p_skey)
        self.pt4_token = cookies.get('pt4_token')
        self.cookies = cookies
        self.headers = {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
        "cache-control": "no-cache",
        "pragma": "no-cache",
        "priority": "u=0, i",
        "sec-ch-ua-mobile": "?0",
        "sec-fetch-dest": "iframe",
        "sec-fetch-mode": "navigate",
        "sec-fetch-site": "same-origin",
        "sec-fetch-user": "?1",
        "upgrade-insecure-requests": "1",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0",
        "referer": "https://user.qzone.qq.com/{}".format(self.QQ),
        }
        if not os.path.exists('user/{}'.format(self.QQ)):
            os.makedirs('user/{}'.format(self.QQ))
        with open('user/{}/cookies.json'.format(self.QQ), 'w',encoding='utf-8') as f:
            json.dump(self.cookies, f)
        with open('user/{}/headers.json'.format(self.QQ), 'w',encoding='utf-8') as f:
            json.dump(self.headers, f)
        if json.loads(self.get_album())['code'] == 0:
            return 1
        else:
            return 0
    def get_album(self):
        url = 'https://user.qzone.qq.com/proxy/domain/photo.qzone.qq.com/fcgi-bin/fcg_list_album_v3'
        params = {
            "g_tk": self.g_tk,
            "callback": "shine0_Callback",
            "t": random.randint(100000000,999999999),
            "hostUin": self.QQ,
            "uin": self.QQ,
            "appid": 4,
            "inCharset": "utf-8",
            "outCharset": "utf-8",
            "source": "qzone",
            "plat": "qzone",
            "format": "jsonp",
            "notice": 0,
            "filter": 1,
            "handset": 4,
            "pageNumModeSort": 40,
            "pageNumModeClass": 15,
            "needUserInfo": 1,
            "idcNum": 4,
            "callbackFun": "shine0",
            "_": int(time.time() * 1000)
        }
        r = requests.get(url,headers=self.headers,cookies=self.cookies,params=params)
        return r.text.split('shine0_Callback(')[1].split(')')[0]
    def get_photo(self,album_id,max_p):
        url = 'https://h5.qzone.qq.com/proxy/domain/photo.qzone.qq.com/fcgi-bin/cgi_list_photo'
        params = {
            "g_tk": self.g_tk,
            "callback": "shine0_Callback",
            "t": random.randint(100000000,999999999),
            'mode':0,
            'idcNum':4,
            "hostUin": self.QQ,
            'topicId':album_id,
            'noTopic':0,
            "uin": self.QQ,
            'pageStart':0,
            'pageNum':max_p,
            'skipCmtCount':0,
            'singleurl':1,
            'batchId': '',
            'notice':0,
            "appid": 4,
            "inCharset": "utf-8",
            "outCharset": "utf-8",
            "source": "qzone",
            "plat": "qzone",
            'outstyle': "json",
            "format": "jsonp",
            'json_esc':1,
            'question':'',
            'anwser':'',
            'callbackFun':'shine0',
            "_": int(time.time() * 1000)
        }
        r = requests.get(url,headers=self.headers,cookies=self.cookies,params=params)
        return r.text.split('shine0_Callback(')[1].split(')')[0]
    def get_all_info(self,albumid,picKey,flag):
        url = 'https://user.qzone.qq.com/proxy/domain/photo.qzone.qq.com/fcgi-bin/cgi_floatview_photo_list_v2'
        params = {
            'g_tk': self.g_tk,
            'callback': 'viewer_Callback',
            't': str(random.randint(100000000, 999999999)),
            'topicId': albumid,
            'picKey': picKey,
            'shootTime': '',
            'cmtOrder': '1',
            'fupdate': '1',
            'plat': 'qzone',
            'source': 'qzone',
            'cmtNum': '10',
            'likeNum': '5',
            'inCharset': 'utf-8',
            'outCharset': 'utf-8',
            'callbackFun': 'viewer',
            'offset': '0',
            'number': '20',
            'uin': self.QQ,
            'hostUin': self.QQ,
            'appid': '4',
            'isFirst': '1',
            'sortOrder': '1',
            'showMode': '1',
            'need_private_comment': '1',
            'prevNum': '0',
            'postNum':'96', # 最大值
            '_': int(time.time() * 1000)
        }
        
        try:
            response = json.loads(requests.get(url, params=params,cookies=self.cookies).text.split('viewer_Callback(')[1].split(')')[0])
            if response['code'] != 0:
                self.get_all_info(albumid,picKey,flag)
            if flag == 1:
                flag=0
            else:
                self.p_info.remove(self.p_info[-1])
            for i in response['data']['photos']:
                name = i['topicName']
                if 'video_info' in i:
                    url = i['video_info']['video_url']
                    type_ =  '.mp4'
                else:
                    url = i['url']
                    type_ =  '.jpg'
                rawshoottime = i['shootTime']
                uploadtime  = i['uploadTime']
                self.p_info.append([name,url,rawshoottime,uploadtime,type_])
            if len(response['data']['photos']) < 97:
                printf(f"相册['{name}']获取完成")
                return 
            self.get_all_info(albumid,response['data']['photos'][-1]['lloc'],flag)
        except Exception as e:
            printf("获取失败，"+str(e),color='red')
        

    def run(self):
        if self.login()==1:
            pass
        else:
            printf("登陆失败",color='red')
            time.sleep(2)
            exit()
        albums_info = json.loads(self.get_album())['data']['albumListModeSort'] # 获取相册信息
        for i in albums_info:
            p = []
            p.append(i['name'])
            p.append(i['id'])
            p.append(i['pre'])
            p.append(i['total'])
            self.a_info.append(p)
        for i in self.a_info:
            if i[-1] == 0:
                continue
            photo = json.loads(self.get_photo(i[1],30))['data']['photoList'] # 获取根据相册获取照片信息
            albumid = i[1]
            picKey = photo[0]['lloc']
            self.get_all_info(albumid, picKey,1)
        self.p_infp = reversed(self.p_info) 
        unique_info = []
        ms = []
        for item in self.p_info:
            m=[]
            m.append(item[0])
            m.append(item[2])
            m.append(item[3])
            m.append(item[4])
            if m not in ms:
                ms.append(m)
                unique_info.append(item)
        self.p_info = unique_info
